using System;
using System.Collections.Generic;
using LocalOverride.Fiddler.Store;
using LocalOverride.Fiddler.UrlMapping;
using LocalOverride.Tests.UI;
using NUnit.Framework;

namespace LocalOverride.Tests.UrlMapping
{
    [TestFixture]
    public class MappingRegistryFactoryTests
    {
        [Test]
        public void Create_WhereStoreEmpty_ReturnsEmptyMapping()
        {
            var factory = new MappingRegistryFactory(new NullStore());

            var overrideMapping = factory.Create();

            var result = overrideMapping.GetMapping(new Uri("http://test.com"));
            Assert.AreEqual(MappingResult.NoMapping, result);
        }

        [Test]
        public void Create_WhereStoreContainsSingleMapping_ReturnsConfiguredOverrideMapping()
        {
            var factory = new MappingRegistryFactory(new TestSingleStore());

            var overrideMapping = factory.Create();

            var result = overrideMapping.GetMapping(new Uri("http://test.com"));
            Assert.AreEqual(@"c:\temp.html", result.LocalFile);
        }

        [Test]
        public void Create_WhereStoreContainsDirectoryMapping_ReturnsConfiguredOverrideMapping()
        {
            var factory = new MappingRegistryFactory(new TestDirectoryStore());

            var overrideMapping = factory.Create();

            var result = overrideMapping.GetMapping(new Uri("http://test.com/blah.html"));
            Assert.AreEqual(@"c:\temp\blah.html", result.LocalFile);
        }


        [Test]
        public void Create_WhereStoreContainsDirectoryMappingWithDownloadSet_ReturnsConfiguredOverrideMappingWithDownloadSet()
        {
            var factory = new MappingRegistryFactory(new TestDirectoryStore());

            var overrideMapping = factory.Create();

            var result = overrideMapping.GetMapping(new Uri("http://test.com/blah.html"));
            Assert.IsTrue(result.DownloadMissingFile);
        }


        [Test]
        public void Create_WhereStoreContainsDirectoryWithDefaultFile_ReturnsDefaultFileForRoot()
        {
            var factory = new MappingRegistryFactory(new TestDirectoryStore());

            var overrideMapping = factory.Create();

            var result = overrideMapping.GetMapping(new Uri("http://test.com/"));
            Assert.AreEqual(result.LocalFile, @"c:\temp\default.html");
        }

        [Test]
        public void Create_WhereStoreContainsDirectoryWithNoDefaultFile_ReturnsDirectoryAsFileName()
        {
            var testDirectoryStore = new TestDirectoryStoreNoDefault();
            
            var factory = new MappingRegistryFactory(testDirectoryStore);

            var overrideMapping = factory.Create();

            var result = overrideMapping.GetMapping(new Uri("http://test.com/blah"));
            Assert.AreEqual(result.LocalFile, @"c:\temp\blah");
        }

        [Test]
        public void Create_WhereStoreContainsDirectoryMappingForCss_ReturnsConfiguredOverrideMapping()
        {
            var factory = new MappingRegistryFactory(new CssOnlyDirectoryStore());

            var overrideMapping = factory.Create();

            var result = overrideMapping.GetMapping(new Uri("http://test.com/blah.css"));
            Assert.AreEqual(@"c:\temp\blah.css", result.LocalFile);
        }

        [Test]
        public void Create_WhereStoreContainsDirectoryMappingForCss_WillNotReturnMappingForHtml()
        {
            var factory = new MappingRegistryFactory(new CssOnlyDirectoryStore());

            var overrideMapping = factory.Create();

            var result = overrideMapping.GetMapping(new Uri("http://test.com/blah.html"));
            Assert.AreEqual(MappingResult.NoMapping, result);
        }

        [Test]
        public void Create_WhenMappingInvalid_WillNotBeAddedToStore()
        {
            var factory = new MappingRegistryFactory(new InvalidEntriesTestStore());

            var overrideMapping = factory.Create();

            var result = overrideMapping.GetMapping(new Uri("http://test.com/blah.html"));
            Assert.AreNotEqual(@"c:\temp\blah.html", result);
        }

        [Test]
        public void Create_WhenSpecialCaseExists_IsReturned()
        {
            var factory = new MappingRegistryFactory(new TestDirectoryStore());

            var overrideMapping = factory.Create();

            var result = overrideMapping.GetMapping(new Uri("http://test.com/blah.axd?id=3"));
            Assert.AreEqual(@"c:\temp\blah_1.axd", result.LocalFile);
        }
    }

    public class BaseTestStore
    {
        public virtual IValidator ValidatorFor(MappingEntry mappingEntry)
        {
            return new PassingValidator();
        }
    }

    public class TestDirectoryStore : BaseTestStore, IMappingStore
    {
        public void Persist()
        {
            throw new NotImplementedException();
        }

        public void AddEntry(MappingEntry mappingEntry)
        {
            throw new NotImplementedException();
        }

        public IEnumerable<MappingEntry> Entries
        {
            get { yield return new MappingEntry { Url = "http://test.com", LocalPath = @"c:\temp", IsDirectory = true, DownloadLocalCopy = true, DefaultFileName = "default.html"}; }
        }

        public void Clear()
        {
            throw new NotImplementedException();
        }

        public void RemoveEntry(MappingEntry mappingEntry)
        {
            throw new NotImplementedException();
        }
    }

    public class TestDirectoryStoreNoDefault : BaseTestStore, IMappingStore
    {
        public void Persist()
        {
            throw new NotImplementedException();
        }

        public void AddEntry(MappingEntry mappingEntry)
        {
            throw new NotImplementedException();
        }

        public IEnumerable<MappingEntry> Entries
        {
            get { yield return new MappingEntry { Url = "http://test.com", LocalPath = @"c:\temp", IsDirectory = true, DownloadLocalCopy = true}; }
        }

        public void Clear()
        {
            throw new NotImplementedException();
        }

        public void RemoveEntry(MappingEntry mappingEntry)
        {
            throw new NotImplementedException();
        }
    }

    public class InvalidEntriesTestStore : TestDirectoryStore
    {
        public override IValidator ValidatorFor(MappingEntry mappingEntry)
        {
            return new FailingValidator();
        }
    }

    public class TestSingleStore : BaseTestStore, IMappingStore
    {
        public void Persist()
        {
            throw new NotImplementedException();
        }

        public void AddEntry(MappingEntry mappingEntry)
        {
            throw new NotImplementedException();
        }

        public IEnumerable<MappingEntry> Entries
        {
            get { yield return new MappingEntry {Url = "http://test.com", LocalPath = @"c:\temp.html"}; }
        }

        public void Clear()
        {
            throw new NotImplementedException();
        }

        public void RemoveEntry(MappingEntry mappingEntry)
        {
            throw new NotImplementedException();
        }
    }

    public class CssOnlyDirectoryStore : BaseTestStore, IMappingStore
    {
        public void Persist()
        {
            throw new NotImplementedException();
        }

        public void AddEntry(MappingEntry mappingEntry)
        {
            throw new NotImplementedException();
        }

        public IEnumerable<MappingEntry> Entries
        {
            get { yield return new MappingEntry { Url = "http://test.com", LocalPath = @"c:\temp", IsDirectory = true, FileExtensions = new FileExtensionList{"css"}}; }
        }

        public void Clear()
        {
            throw new NotImplementedException();
        }

        public void RemoveEntry(MappingEntry mappingEntry)
        {
            throw new NotImplementedException();
        }
    }

    public class NullStore : BaseTestStore, IMappingStore
    {
        public void Persist()
        {
            throw new NotImplementedException();
        }

        public void AddEntry(MappingEntry mappingEntry)
        {
            throw new NotImplementedException();
        }

        public IEnumerable<MappingEntry> Entries
        {
            get { yield break; }
        }

        public void Clear()
        {
            throw new NotImplementedException();
        }

        public void RemoveEntry(MappingEntry mappingEntry)
        {
            throw new NotImplementedException();
        }
    }
}